package org.study.r2dbc.boot.service;

import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.r2dbc.core.R2dbcEntityTemplate;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.study.r2dbc.boot.model.User;
import org.study.r2dbc.boot.repository.UserRepository;
import reactor.core.publisher.Flux;
import reactor.core.publisher.Mono;

import java.math.BigDecimal;

/**
 * 作用描述
 *
 * @author doveylovey
 * @version v1.0.0
 * @email 1135782208@qq.com
 * @date 2025年04月02日
 */
@Slf4j
@RequiredArgsConstructor(onConstructor = @__(@Autowired))
@Service
public class UserServiceImplByRepository implements UserServiceByRepository {
    private final UserRepository userRepository;
    private final R2dbcEntityTemplate r2dbcEntityTemplate;

    @Override
    public Flux<User> findAll() {
        return userRepository.findAll();
    }

    @Override
    public Mono<User> findById(Long id) {
        return userRepository.findById(id);
    }

    @Override
    public Flux<User> findByName(String name) {
        return userRepository.findByName(name);
    }

    @Override
    public Flux<User> findByEmail(String email) {
        return userRepository.findByEmail(email);
    }

    @Override
    public Flux<User> findByAgeGreaterThan(int age) {
        return userRepository.findByAgeGreaterThan(age);
    }

    @Override
    public Mono<User> saveUser(User user) {
        // 先检查ID是否已存在
        return userRepository.existsById(user.getId())
                .flatMap(exists -> {
                    if (exists) {
                        return Mono.error(new RuntimeException("当前用户ID：" + user.getId() + "已存在"));
                    }
                    return r2dbcEntityTemplate.insert(user);
                });
    }

    @Override
    public Mono<User> updateUser(Long id, User user) {
        return userRepository.findById(id)
                .flatMap(existingUser -> {
                    existingUser.setName(user.getName());
                    existingUser.setEmail(user.getEmail());
                    existingUser.setAge(user.getAge());
                    return userRepository.save(existingUser);
                });
    }

    @Override
    public Mono<Void> deleteUser(Long id) {
        return userRepository.deleteById(id);
    }

    @Transactional
    @Override
    public Mono<Void> transferMoney(Long fromId, Long toId, BigDecimal amount) {
        return userRepository.findById(fromId)
                .flatMap(from -> {
                    from.setBalance(from.getBalance().subtract(amount));
                    return userRepository.save(from);
                })
                .then(userRepository.findById(toId))
                .flatMap(to -> {
                    to.setBalance(to.getBalance().add(amount));
                    return userRepository.save(to);
                })
                .then();
    }
}
